﻿using System;
using SimpleServiceBus.Bus;
using SimpleServiceBus.Endpoint;
using SimpleServiceBus.Tests.Stubs;
using NUnit.Framework;

namespace SimpleServiceBus.Tests.Endpoint
{
    [TestFixture]
    public class MessagingEndpointTestFixture
    {
        private int _onlineCount;
        private int _offlineCount;
        private EndpointEventArgs _onlineArgs;
        private EndpointOfflineEventArgs _offlineArgs;


        private void ClearEventHistory()
        {
            _onlineCount = 0;
            _offlineCount = 0;
            _onlineArgs = null;
            _offlineArgs = null;
        }

        private void ListenToEndpoint(IMessagingEndpoint endpoint)
        {
            ClearEventHistory();
            endpoint.EndpointOnline += endpoint_EndpointOnline;
            endpoint.EndpointOffline += endpoint_EndpointOffline;
            endpoint.MessageBus.MessageProcessingException += endpoint_ServiceException;
        }

        private void StopListeningToEndpoint(IMessagingEndpoint endpoint)
        {
            endpoint.EndpointOnline -= endpoint_EndpointOnline;
            endpoint.EndpointOffline -= endpoint_EndpointOffline;
            endpoint.MessageBus.MessageProcessingException -= endpoint_ServiceException;
        }


        private static void endpoint_ServiceException(object sender, MessageProcessingErrorEventArgs e)
        {
            throw e.Exception;
        }

        private void endpoint_EndpointOffline(object sender, EndpointOfflineEventArgs e)
        {
            _offlineCount++;
            _offlineArgs = e;
        }

        private void endpoint_EndpointOnline(object sender, EndpointEventArgs e)
        {
            _onlineCount++;
            _onlineArgs = e;
        }

        [Test]
        public void RestartAndTakeOfflineViaRestartTest()
        {
            Console.WriteLine("restarttest");
            IMessagingEndpoint endpoint = TestEndpoint.Create();
            endpoint.LocalServices.RegisterService(new TestBackgroundService());


            ListenToEndpoint(endpoint);

            endpoint.Start();
            endpoint.Restart("Restart Test");

            Assert.IsNotNull(endpoint);
            Assert.IsNotNull(endpoint.MessageBus);
            Assert.IsNotNull(((TestBus) endpoint.MessageBus).Transport);
            Assert.IsTrue(endpoint.IsRunning);

            Assert.AreEqual(2, _onlineCount);
            Assert.AreEqual(1, _offlineCount);

            Assert.AreEqual("Restarting. Reason: Restart Test", _offlineArgs.Reason);
            Assert.AreEqual(1, _offlineArgs.EstimatedOutageInMinutes);

            endpoint.Stop();

            Assert.AreEqual(2, _onlineCount);
            Assert.AreEqual(2, _offlineCount);

            StopListeningToEndpoint(endpoint);
        }

        [Test]
        public void StartStopTest()
        {
            Console.WriteLine("startstoptest");
            IMessagingEndpoint endpoint = TestEndpoint.Create();
            endpoint.LocalServices.RegisterService(new TestBackgroundService());

            Assert.IsNotNull(endpoint);
            Assert.IsNotNull(endpoint.MessageBus);

            ListenToEndpoint(endpoint);

            endpoint.Start();

            Assert.IsNotNull(((TestBus)endpoint.MessageBus).Transport);


            Assert.IsNotNull(((TestEndpoint) endpoint).PublicLocalServices);
            Assert.IsTrue(endpoint.LocalServices.HasService<TestBackgroundService>());
            Assert.IsTrue(endpoint.LocalServices.GetService<TestBackgroundService>().IsRunning);

            //Assert.AreEqual(1, ((TestEndpoint) endpoint).RegisteredMessageHandlerAssemblies.Count);
            //Assert.AreSame(GetType().Assembly, ((TestEndpoint) endpoint).RegisteredMessageHandlerAssemblies[0]);

            endpoint.Stop();


            Assert.IsFalse(endpoint.LocalServices.GetService<TestBackgroundService>().IsRunning);

            StopListeningToEndpoint(endpoint);

            Assert.AreEqual(1, _onlineCount);
            Assert.AreEqual(1, _offlineCount);

            Assert.AreEqual(endpoint.Metadata.EndpointID, _onlineArgs.EndpointID);
            Assert.AreEqual(endpoint.Metadata.EndpointID, _offlineArgs.EndpointID);
        }
    }
}